package com.xwintop.xTransfer.receiver.service.impl;

import com.xwintop.xTransfer.common.MsgLogger;
import com.xwintop.xTransfer.common.model.LOGKEYS;
import com.xwintop.xTransfer.common.model.LOGVALUES;
import com.xwintop.xTransfer.common.model.Msg;
import com.xwintop.xTransfer.messaging.MessageHandler;
import com.xwintop.xTransfer.receiver.bean.ReceiverConfig;
import com.xwintop.xTransfer.receiver.bean.ReceiverConfigFtpServer;
import com.xwintop.xTransfer.receiver.service.Receiver;
import com.xwintop.xTransfer.task.quartz.TaskQuartzJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ftpserver.ConnectionConfig;
import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.Authority;
import org.apache.ftpserver.impl.DefaultConnectionConfig;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.ssl.SslConfigurationFactory;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.TransferRatePermission;
import org.apache.ftpserver.usermanager.impl.WritePermission;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: ReceiverFtpServerImpl
 * @Description: FtpServer接收器实现类
 * @author: xufeng
 * @date: 2018/4/9 11:27
 */
@Service("receiverFtpServer")
@Scope("prototype")
@Slf4j
public class ReceiverFtpServerImpl implements Receiver {
    private ReceiverConfigFtpServer receiverConfigFtpServer;
    private MessageHandler messageHandler;
    FtpServer ftpServer = null;

    @Override
    public void receive(Map params) throws Exception {
        log.debug("ReceiverFtpServerImpl开始执行");
        this.checkInit(params);
    }

    @Override
    public void setReceiverConfig(ReceiverConfig receiverConfig) {
        this.receiverConfigFtpServer = (ReceiverConfigFtpServer) receiverConfig;
    }

    @Override
    public void setMessageHandler(MessageHandler messageHandler) {
        this.messageHandler = messageHandler;
    }

    @Override
    public void destroy() {
        if (ftpServer != null && !ftpServer.isStopped()) {
            ftpServer.stop();
            ftpServer = null;
        }
    }

    private synchronized void checkInit(Map params) throws Exception {
        if (ftpServer == null) {
            FtpServerFactory ftpServerFactory = new FtpServerFactory();
            ListenerFactory factory = new ListenerFactory();
            factory.setPort(receiverConfigFtpServer.getPort());
            if (StringUtils.isNotEmpty(receiverConfigFtpServer.getKeystoreFilePath())) {
                // define SSL configuration
                SslConfigurationFactory ssl = new SslConfigurationFactory();
                ssl.setKeystoreFile(new File(receiverConfigFtpServer.getKeystoreFilePath()));
                ssl.setKeystorePassword(receiverConfigFtpServer.getKeystorePassword());
                // set the SSL configuration for the listener
                factory.setSslConfiguration(ssl.createSslConfiguration());
                factory.setImplicitSsl(true);
            }

            ConnectionConfig connectionConfig = new DefaultConnectionConfig(receiverConfigFtpServer.isAnonymousLoginEnabled(), receiverConfigFtpServer.getLoginFailureDelay(), receiverConfigFtpServer.getMaxLogins(), receiverConfigFtpServer.getMaxAnonymousLogins(), receiverConfigFtpServer.getMaxLoginFailures(), receiverConfigFtpServer.getMaxThreads());
            ftpServerFactory.setConnectionConfig(connectionConfig);
            if (receiverConfigFtpServer.isAnonymousLoginEnabled()) {
                BaseUser user = new BaseUser();
                user.setName("anonymous");
                user.setHomeDirectory(receiverConfigFtpServer.getAnonymousHomeDirectory());
                List<Authority> authorities = new ArrayList<Authority>();
                authorities.add(new WritePermission());// 添加用户读写权限
                user.setAuthorities(authorities);
                ftpServerFactory.getUserManager().save(user);
            }

            if (CollectionUtils.isNotEmpty(receiverConfigFtpServer.getFtpServerUserList())) {
                for (ReceiverConfigFtpServer.FtpServerUser ftpServerUser : receiverConfigFtpServer.getFtpServerUserList()) {
                    BaseUser user = new BaseUser();
                    user.setName(ftpServerUser.getName());
                    user.setPassword(ftpServerUser.getPassword());
                    user.setHomeDirectory(ftpServerUser.getHomeDir());
                    user.setEnabled(ftpServerUser.isEnabled());
                    List<Authority> authorities = new ArrayList<Authority>();
                    authorities.add(new TransferRatePermission(ftpServerUser.isDownFile() ? Integer.MAX_VALUE : 0, ftpServerUser.isUpFile() ? Integer.MAX_VALUE : 0));
                    if (ftpServerUser.isDeleteFile()) {
                        authorities.add(new WritePermission());// 添加用户读写权限
                    }
                    user.setAuthorities(authorities);
                    ftpServerFactory.getUserManager().save(user);
                }
            }

            ftpServerFactory.addListener("default", factory.createListener());
            ftpServer = ftpServerFactory.createServer();
            ftpServer.start();
            Msg msgLogInfo = new Msg(LOGVALUES.EVENT_MSG_RECEIVED, null, null);
            msgLogInfo.put(LOGKEYS.CHANNEL_IN_TYPE, LOGVALUES.CHANNEL_TYPE_FTP_SERVER);
//            msgLogInfo.put(LOGKEYS.CHANNEL_IN, receiverConfigFtpServer.getVirtualHost() + ":" + receiverConfigFtpServer.getTopic());
//            msgLogInfo.put(LOGKEYS.MSG_TAG, msg.getFileName());
//            msgLogInfo.put(LOGKEYS.MSG_LENGTH, ArrayUtils.getLength(msg.getMessage()));
            msgLogInfo.put(LOGKEYS.JOB_ID, params.get(TaskQuartzJob.JOBID));
            msgLogInfo.put(LOGKEYS.JOB_SEQ, params.get(TaskQuartzJob.JOBSEQ));
            msgLogInfo.put(LOGKEYS.RECEIVER_TYPE, LOGVALUES.CHANNEL_TYPE_FTP_SERVER);
            msgLogInfo.put(LOGKEYS.RECEIVER_ID, receiverConfigFtpServer.getId());
            MsgLogger.info(msgLogInfo.toMap());
        }
    }
}
